
#include <windows.h>
#include <stdarg.h>
#include <time.h>
#include "lib.h"
#include "log.h"
#include "logger.h"

#include "opts.h"

Logger* Log::logger = (Logger*)0;

// New log in text file
pFileStream Log::fs = (pFileStream)0;
String Log::strAppName="";
String Log::strFullPathAppName="";
PCRITICAL_SECTION Log::iolog=(PCRITICAL_SECTION)0;


void
Log::init(Logger* newLogger)
{
	logger = newLogger;

	// CGC. New log in text file
	fs = new FileStream();

	// CGC. New log in text file. Get app name
	wchar_t        szAppPath[MAX_PATH];
	::GetModuleFileName(NULL, szAppPath, MAX_PATH);
	strFullPathAppName = szAppPath;
	strAppName = szAppPath;
	strAppName = strAppName.substring(strAppName.reverseFind('\\') + 1, MAX_PATH);
	strAppName = strAppName.substring(0, strAppName.reverseFind('.'));

	// CGC. Initialize critical section for text file log
	iolog = new CRITICAL_SECTION;
	if (iolog)
		InitializeCriticalSection(iolog);
	else
	{
		delete iolog;
		iolog = (PCRITICAL_SECTION)0;
	}
}

void
Log::uninit()
{
	if (logger)
	{
		if (logger->logCanDeleteLogger())
			delete logger;

		logger = (Logger*)0;

		if (fs != 0)
		{
			delete fs;
			fs = 0;
		}

		if (iolog)
		{
			DeleteCriticalSection(iolog);
			delete iolog;
			iolog = (PCRITICAL_SECTION)0;
		}
	}
}

void
Log::msgError(const char* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG
	if (logger)
		logger->logMsgError(fmt, arg);
#endif

	// CGC: new log in text file
	LogEventTextFile(2, fmt, arg);

	va_end(arg);
}

// CGC 16/11/2010: PID in log (CSN-3067)
void
Log::msgErrorPID(String Pid, const char* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG
	if (logger)
		logger->logMsgError(fmt, arg);
#endif

	// CGC: new log in text file
	LogEventTextFile(Pid, 2, fmt, arg);

	va_end(arg);
}

//RPF New message member
void
Log::msg(int32 level,const char* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
/*#ifdef _DEBUG
	if (logger)
		logger->logMsgError(fmt, arg);
#endif
*/   

	// CGC: new log in text file
	LogEventTextFile(level, fmt, arg);

    va_end(arg);
}

void
Log::msg(int32 level,const wchar_t* fmt,...)
{
	
    va_list arg;
    va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
/*#ifdef _DEBUG	
	if (logger)
		logger->logMsgError(fmt, arg);
#endif
*/
    	// CGC: new log in text file
	LogEventTextFile(level, fmt, arg);
    
    va_end(arg);
	
}



void
Log::msgWarning(const char* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG
	if (logger)
		logger->logMsgWarning(fmt, arg);
#endif

    // CGC: new log in text file
	LogEventTextFile(3, fmt, arg);

	va_end(arg);
}

// CGC 16/11/2010: PID in log (CSN-3067)
void
Log::msgWarningPID(String Pid, const char* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG
	if (logger)
		logger->logMsgWarning(fmt, arg);
#endif

    // CGC: new log in text file
	LogEventTextFile(Pid, 3, fmt, arg);

	va_end(arg);
}

void
Log::msgInformation(const char* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG
	if (logger)
		logger->logMsgInformation(fmt, arg);
#endif

	// CGC: new log in text file
	LogEventTextFile(4, fmt, arg);

	va_end(arg);
}

// CGC 16/11/2010: PID in log (CSN-3067)
void
Log::msgInformationPID(String Pid, const char* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG
	if (logger)
		logger->logMsgInformation(fmt, arg);
#endif

	// CGC: new log in text file
	LogEventTextFile(Pid, 4, fmt, arg);

	va_end(arg);
}

void
Log::msgError(const wchar_t* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG	
	if (logger)
		logger->logMsgError(fmt, arg);
#endif

	// CGC: new log in text file
	LogEventTextFile(2, fmt, arg);

	va_end(arg);
}

// CGC 16/11/2010: PID in log (CSN-3067)
void
Log::msgErrorPID(String Pid, const wchar_t* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG	
	if (logger)
		logger->logMsgError(fmt, arg);
#endif

	// CGC: new log in text file
	LogEventTextFile(Pid, 2, fmt, arg);

	va_end(arg);
}

void
Log::msgWarning(const wchar_t* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG
	if (logger)
		logger->logMsgWarning(fmt, arg);
#endif

	// CGC: new log in text file
	LogEventTextFile(3, fmt, arg);

	va_end(arg);
}

// CGC 16/11/2010: PID in log (CSN-3067)
void
Log::msgWarningPID(String Pid, const wchar_t* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG
	if (logger)
		logger->logMsgWarning(fmt, arg);
#endif

	// CGC: new log in text file
	LogEventTextFile(Pid, 3, fmt, arg);

	va_end(arg);
}

void
Log::msgInformation(const wchar_t* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG	
	if (logger)
		logger->logMsgInformation(fmt, arg);
#endif

	// CGC: new log in text file
	LogEventTextFile(4, fmt, arg);

	va_end(arg);
}

// CGC 16/11/2010: PID in log (CSN-3067)
void
Log::msgInformationPID(String Pid, const wchar_t* fmt, ...)
{
	va_list arg;
	va_start(arg, fmt);

// CGC: no log in event viewer if we are in release mode
#ifdef _DEBUG	
	if (logger)
		logger->logMsgInformation(fmt, arg);
#endif

	// CGC: new log in text file
	LogEventTextFile(Pid, 4, fmt, arg);

	va_end(arg);
}

void
Log::numUsers(int32 Users,String strAppName)
{
	if (logger)
		logger->logNumUsers(Users,strAppName);
}

void
Log::stoppingCheckpoint()
{
	if (logger)
		logger->logStoppingCheckpoint();
}

// CGC: new log in text file (char*)
void 
Log::LogEventTextFile(int32 level, const char* fmt, va_list args)
{
	if (level <= ServerOpts::logAppLevel && fs != 0)
	{
		SYSTEMTIME st;
        GetLocalTime(&st);
        String dateStr;
		String typeStr;
      
        if(level<=1)
            typeStr="CRITICAL";
        else if (level==2)
            typeStr="ERROR";
        else if (level==3)
            typeStr="WARNING";
        else if (level==4)
            typeStr="INFO";
        else if (level>=5)
            typeStr="DEBUG";

        char strType[15];
        wcstombs(strType, typeStr, 15);
        dateStr.sprintf("%d%02d%02d",st.wYear,st.wMonth,st.wDay);
		char timeTypeStr[30];
		sprintf(timeTypeStr,"%02d:%02d:%02d (%s) ",st.wHour,st.wMinute,st.wSecond, strType );
           

		// Log file name: "Directory\appname_YYYYMMDD.log"
		String strAppNameLog = ServerOpts::logDirectory + strAppName + String("_") + dateStr + String(".log");		
		

		char buff[2048];
		wvsprintfA(buff, fmt, args);

		// Ensure unique access to log file
		if (iolog)
			EnterCriticalSection(iolog);
		
		try
		{
			// Open file: we try up to 5 times, in case other process (ex. opening file with notepad)
			// has blocked the file
			int nTry = 1;
			bool8 opened = fs->open(strAppNameLog, FileStream::appending);			
			while (!opened && nTry<=5)
			{
				Sleep(500);
				opened = fs->open(strAppNameLog, FileStream::appending);
				nTry++;
			}

			if (opened)
			{
				// Write log + new line
				fs->write((void*)timeTypeStr, strlen(timeTypeStr));
				fs->write((void*)buff, strlen(buff));
				fs->write("\r\n", 2);
				fs->close();
			}
		}
		catch(...)
		{}

		if (iolog)
			LeaveCriticalSection(iolog);
	}	
}

// CGC: new log in text file (char*)
void 
Log::LogEventTextFile(String Pid, int32 level, const char* fmt, va_list args)
{
	if (level <= ServerOpts::logAppLevel && fs != 0)
	{
		SYSTEMTIME st;
        GetLocalTime(&st);
        String dateStr;
		String typeStr;
      
        if(level<=1)
            typeStr="CRITICAL";
        else if (level==2)
            typeStr="ERROR";
        else if (level==3)
            typeStr="WARNING";
        else if (level==4)
            typeStr="INFO";
        else if (level>=5)
            typeStr="DEBUG";

        char strType[15];
        wcstombs(strType, typeStr, 15);
        dateStr.sprintf("%d%02d%02d",st.wYear,st.wMonth,st.wDay);
		char timeTypeStr[30];
		sprintf(timeTypeStr,"%02d:%02d:%02d [%S] (%s) ",st.wHour,st.wMinute,st.wSecond, (const uint16*) Pid, strType );
           

		// Log file name: "Directory\appname_YYYYMMDD.log"
		String strAppNameLog = ServerOpts::logDirectory + strAppName + String("_") + dateStr + String(".log");		
		

		char buff[2048];
		wvsprintfA(buff, fmt, args);

		// Ensure unique access to log file
		if (iolog)
			EnterCriticalSection(iolog);
		
		try
		{
			// Open file: we try up to 5 times, in case other process (ex. opening file with notepad)
			// has blocked the file
			int nTry = 1;
			bool8 opened = fs->open(strAppNameLog, FileStream::appending);			
			while (!opened && nTry<=5)
			{
				Sleep(500);
				opened = fs->open(strAppNameLog, FileStream::appending);
				nTry++;
			}

			if (opened)
			{
				// Write log + new line
				fs->write((void*)timeTypeStr, strlen(timeTypeStr));
				fs->write((void*)buff, strlen(buff));
				fs->write("\r\n", 2);
				fs->close();
			}
		}
		catch(...)
		{}

		if (iolog)
			LeaveCriticalSection(iolog);
	}	
}

// CGC: new log in text file (wchar_t*)
void 
Log::LogEventTextFile(int32 level,const wchar_t* fmt, va_list args)
{
	if (level <= ServerOpts::logAppLevel && fs != 0)
	{
		SYSTEMTIME st;
        GetLocalTime(&st);
        String dateStr;
		String typeStr;
      
        if(level<=1)
            typeStr="CRITICAL";
        else if (level==2)
            typeStr="ERROR";
        else if (level==3)
            typeStr="WARNING";
        else if (level==4)
            typeStr="INFO";
        else if (level>=5)
            typeStr="DEBUG";

        char strType[15];
        wcstombs(strType, typeStr, 15);

	
		dateStr.sprintf("%d%02d%02d",st.wYear,st.wMonth,st.wDay);
		char timeTypeStr[30];
		sprintf(timeTypeStr,"%02d:%02d:%02d (%s) ",st.wHour,st.wMinute,st.wSecond, strType);


		// Log file name: "Directory\appname_YYYYMMDD.log"
		String strAppNameLog = ServerOpts::logDirectory + strAppName + String("_") + dateStr + String(".log");

		// wchar_t -> char 
		char pAux[2048];
		wcstombs(pAux, fmt, 2048);

		char buff[2048];
		wvsprintfA(buff, pAux, args);
       

		// Ensure unique access to log file
		if (iolog)
			EnterCriticalSection(iolog);
		
		try
		{
			// Open file: we try up to 5 times, in case other process (ex. opening file with notepad)
			// has blocked the file
			int nTry = 1;
			bool8 opened = fs->open(strAppNameLog, FileStream::appending);			
			while (!opened && nTry<=5)
			{
				Sleep(500);
				opened = fs->open(strAppNameLog, FileStream::appending);
				nTry++;
			}

			if (opened)
			{				
				// Write log + new line
				fs->write((void*)timeTypeStr, strlen(timeTypeStr));
				fs->write((void*)pAux, strlen(pAux));
				fs->write("\r\n", 2);
				fs->close();
			}
		}
		catch(...)
		{}
		
		if (iolog)
			LeaveCriticalSection(iolog);		
	}	
}

// CGC: new log in text file (wchar_t*)
void 
Log::LogEventTextFile(String Pid, int32 level,const wchar_t* fmt, va_list args)
{
	if (level <= ServerOpts::logAppLevel && fs != 0)
	{
		SYSTEMTIME st;
        GetLocalTime(&st);
        String dateStr;
		String typeStr;
      
        if(level<=1)
            typeStr="CRITICAL";
        else if (level==2)
            typeStr="ERROR";
        else if (level==3)
            typeStr="WARNING";
        else if (level==4)
            typeStr="INFO";
        else if (level>=5)
            typeStr="DEBUG";

        char strType[15];
        wcstombs(strType, typeStr, 15);

	
		dateStr.sprintf("%d%02d%02d",st.wYear,st.wMonth,st.wDay);
		char timeTypeStr[30];
		sprintf(timeTypeStr,"%02d:%02d:%02d [%S] (%s) ",st.wHour,st.wMinute,st.wSecond, (const uint16*) Pid, strType);


		// Log file name: "Directory\appname_YYYYMMDD.log"
		String strAppNameLog = ServerOpts::logDirectory + strAppName + String("_") + dateStr + String(".log");

		// wchar_t -> char 
		char pAux[2048];
		wcstombs(pAux, fmt, 2048);

		char buff[2048];
		wvsprintfA(buff, pAux, args);
       

		// Ensure unique access to log file
		if (iolog)
			EnterCriticalSection(iolog);
		
		try
		{
			// Open file: we try up to 5 times, in case other process (ex. opening file with notepad)
			// has blocked the file
			int nTry = 1;
			bool8 opened = fs->open(strAppNameLog, FileStream::appending);			
			while (!opened && nTry<=5)
			{
				Sleep(500);
				opened = fs->open(strAppNameLog, FileStream::appending);
				nTry++;
			}

			if (opened)
			{				
				// Write log + new line
				fs->write((void*)timeTypeStr, strlen(timeTypeStr));
				fs->write((void*)pAux, strlen(pAux));
				fs->write("\r\n", 2);
				fs->close();
			}
		}
		catch(...)
		{}
		
		if (iolog)
			LeaveCriticalSection(iolog);		
	}	
}

// CSB-7499 - Expose the version on RTG services
void Log::msgStart()		// Log module name + version info
{
	
	DWORD dwVerInfoSize;
	DWORD dwVerHnd;
	BYTE  *pBuffer = NULL;
	LPCTSTR obuffer;
	UINT   Len    = 0;

	// Get version info
	dwVerInfoSize = GetFileVersionInfoSize(strFullPathAppName, &dwVerHnd);
	if (dwVerInfoSize)
	{
		pBuffer = (BYTE*)malloc(dwVerInfoSize);
		if (pBuffer){
			if (GetFileVersionInfo(strFullPathAppName, dwVerHnd, dwVerInfoSize, pBuffer)){				
                VerQueryValue(pBuffer, TEXT("\\StringFileInfo\\040904B0\\FileVersion"), (void**)&obuffer, &Len);
				
				// If we have both module name and version, log them
				// We ALWAYS want to print this message, no matter the log level. So we set it to 5 and then restore it
				int32 iCurrentLogLevel = ServerOpts::logAppLevel;
				ServerOpts::logAppLevel = 5;
				msgInformation("STARTING %S, %S version", (const uint16*)strFullPathAppName, obuffer);	
				ServerOpts::logAppLevel = iCurrentLogLevel;
			}
			free(pBuffer);
		}
	}

}